import { appConfig } from "../config/appConfig";
import type {
  BootstrapResponse,
  CategoryItem,
  MenuItem,
  OrderLineItem,
  OrderRecord,
  OrderStatus,
  UserProfile,
} from "../types/entities";
import type {
  MenuCreatePayload,
  MenuListResponse,
  MenuRemovePayload,
  MenuRemoveResponse,
  MenuSavePayload,
  MenuSaveResponse,
  OrderListParams,
  OrderListResponse,
  OrderSubmitPayload,
  OrderSubmitResponse,
  OrderUpdateResponse,
  ReviewSubmitPayload,
  ReviewSubmitResponse,
} from "../types/dto";

type RoleType = "chef" | "diner";

interface LocalUser extends UserProfile {
  password: string;
}

interface LocalMenuItem extends MenuItem {}

interface LocalOrder extends OrderRecord {}

interface LocalDB {
  users: LocalUser[];
  categories: CategoryItem[];
  menu: LocalMenuItem[];
  orders: LocalOrder[];
}

const STORAGE_KEY = appConfig.localStorageKey;
const USER_KEY = appConfig.localUserKey;
const DB_FILE_PATH = `${wx.env.USER_DATA_PATH}/${STORAGE_KEY}.json`;

const LEGACY_COVER_URLS: Record<string, string> = {
  "https://img01.yzcdn.cn/vant/cake.png": "/assets/images/rice.png",
  "https://img01.yzcdn.cn/vant/muffin.png": "/assets/images/muffin.png",
};

function getFs() {
  return typeof wx.getFileSystemManager === "function" ? wx.getFileSystemManager() : null;
}

function readDBFromFile(): LocalDB | null {
  const fs = getFs();
  if (!fs) return null;
  try {
    const content = fs.readFileSync(DB_FILE_PATH, "utf-8") as string;
    const parsed = JSON.parse(content) as LocalDB;
    if (Array.isArray(parsed?.users)) {
      return parsed;
    }
  } catch (error) {
    // ignore
  }
  return null;
}

function writeDBToFile(db: LocalDB) {
  const fs = getFs();
  if (!fs) return;
  try {
    fs.writeFileSync(DB_FILE_PATH, JSON.stringify(db), "utf-8");
  } catch (error) {
    console.warn("写入本地文件失败", error);
  }
}

function generateId(prefix: string) {
  return `${prefix}_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
}

function createDefaultDB(): LocalDB {
  const chefOpenId = generateId("user");
  const dinerOpenId = generateId("user");

  const users: LocalUser[] = [
    {
      _id: generateId("user"),
      _openid: chefOpenId,
      account: "chef",
      nickname: "心动大厨",
      avatarUrl: "https://img01.yzcdn.cn/vant/cat.jpeg",
      role: "chef",
      createdAt: new Date().toISOString(),
      password: "chef123",
    },
    {
      _id: generateId("user"),
      _openid: dinerOpenId,
      account: "diner",
      nickname: "宠爱食客",
      avatarUrl: "https://img.yzcdn.cn/vant/logo.png",
      role: "diner",
      createdAt: new Date().toISOString(),
      password: "diner123",
    },
  ];

  const categories: CategoryItem[] = [
    { key: "stirfry", name: "炒菜", color: "#FF9A9E", icon: "🍲" },
    { key: "rice", name: "米饭", color: "#FBC2EB", icon: "🍚" },
    { key: "fruit", name: "水果", color: "#8EC5FC", icon: "🍉" },
    { key: "whole", name: "粗粮", color: "#A1FFCE", icon: "🥖" },
    { key: "snack", name: "零食", color: "#FAD0C4", icon: "🍪" },
  ];

  const menu: LocalMenuItem[] = [
    {
      _id: generateId("menu"),
      chefOpenId,
      categoryKey: "stirfry",
      name: "花椒嫩牛",
      description: "带一点麻有一点甜，吃完像被拥抱",
      coverUrl: "https://img01.yzcdn.cn/vant/leaf.jpg",
      stock: 6,
      funValue: 5,
      isActive: true,
      createdAt: new Date().toISOString(),
    },
    {
      _id: generateId("menu"),
      chefOpenId,
      categoryKey: "rice",
      name: "云朵米饭",
      description: "撒上芝士雪花的软糯白米",
      coverUrl: "/assets/images/rice.png",
      stock: 8,
      funValue: 3,
      isActive: true,
      createdAt: new Date().toISOString(),
    },
    {
      _id: generateId("menu"),
      chefOpenId,
      categoryKey: "fruit",
      name: "彩虹果盘",
      description: "五种颜色的当季水果拼盘",
      coverUrl: "https://img01.yzcdn.cn/vant/apple-1.jpg",
      stock: 4,
      funValue: 4,
      isActive: true,
      createdAt: new Date().toISOString(),
    },
    {
      _id: generateId("menu"),
      chefOpenId,
      categoryKey: "whole",
      name: "小麦暖吐司",
      description: "烤得刚好，上桌自带温度",
      coverUrl: "/assets/images/muffin.png",
      stock: 5,
      funValue: 2,
      isActive: true,
      createdAt: new Date().toISOString(),
    },
    {
      _id: generateId("menu"),
      chefOpenId,
      categoryKey: "snack",
      name: "甜心能量球",
      description: "可可与坚果结合的手作小点",
      coverUrl: "https://img.yzcdn.cn/vant/logo.png",
      stock: 10,
      funValue: 6,
      isActive: true,
      createdAt: new Date().toISOString(),
    },
  ];

  return {
    users,
    categories,
    menu,
    orders: [],
  };
}

function ensureDB(): LocalDB {
  let db = readDBFromFile();
  if (!db || !Array.isArray(db.users) || !db.users.length) {
    db = wx.getStorageSync<LocalDB>(STORAGE_KEY);
  }
  if (!db || !Array.isArray(db.users) || !db.users.length) {
    db = createDefaultDB();
    wx.setStorageSync(STORAGE_KEY, db);
    writeDBToFile(db);
  }
  migrateLegacyAssets(db);
  return db;
}

function saveDB(db: LocalDB) {
  wx.setStorageSync(STORAGE_KEY, db);
  writeDBToFile(db);
}

function migrateLegacyAssets(db: LocalDB) {
  let updated = false;
  db.menu.forEach((item) => {
    const mapped = LEGACY_COVER_URLS[item.coverUrl];
    if (mapped && mapped !== item.coverUrl) {
      item.coverUrl = mapped;
      updated = true;
    }
  });
  if (updated) {
    saveDB(db);
  }
}

function getActiveUser(db: LocalDB): LocalUser | null {
  const openId = wx.getStorageSync<string>(USER_KEY);
  if (!openId) return null;
  return db.users.find((user) => user._openid === openId) || null;
}

function setActiveUser(user: LocalUser | null) {
  if (!user) {
    wx.removeStorageSync(USER_KEY);
  } else {
    wx.setStorageSync(USER_KEY, user._openid);
  }
}

function sanitizeUser(user: LocalUser): UserProfile {
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  const { password, ...rest } = user;
  return rest;
}

function cloneMenuItem(item: LocalMenuItem): MenuItem {
  return { ...item };
}

function sanitizeOrder(order: LocalOrder): OrderRecord {
  return {
    ...order,
    items: order.items.map((item) => ({ ...item })),
    review: order.review ? { ...order.review } : undefined,
  };
}

function requireUser(db: LocalDB): LocalUser {
  const user = getActiveUser(db);
  if (!user) {
    throw new Error("请先登录");
  }
  return user;
}

function requireChef(db: LocalDB): LocalUser {
  const user = requireUser(db);
  if (user.role !== "chef") {
    throw new Error("请使用厨师账号");
  }
  return user;
}

function requireDiner(db: LocalDB): LocalUser {
  const user = requireUser(db);
  if (user.role !== "diner") {
    throw new Error("请使用点餐账号");
  }
  return user;
}

function filterOrdersForUser(db: LocalDB, user: LocalUser | null, status?: OrderStatus): LocalOrder[] {
  if (!user) return [];
  const list = db.orders.filter((order) => {
    if (user.role === "chef") {
      return order.chefOpenId === user._openid;
    }
    return order.dinerOpenId === user._openid;
  });
  const filtered = typeof status === "string" ? list.filter((item) => item.status === status) : list;
  return filtered.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
}

function bootstrap(): BootstrapResponse {
  const db = ensureDB();
  const user = getActiveUser(db);
  return {
    envId: "local",
    userProfile: user ? sanitizeUser(user) : null,
    categories: db.categories.map((item) => ({ ...item })),
    menu: db.menu.map(cloneMenuItem),
    orders: filterOrdersForUser(db, user).map(sanitizeOrder),
  };
}

function listMenu(): MenuListResponse {
  const db = ensureDB();
  return {
    menu: db.menu.map(cloneMenuItem),
  };
}

function createMenu(payload: MenuCreatePayload): MenuSaveResponse {
  const db = ensureDB();
  const chef = requireChef(db);
  const name = (payload.name || "").trim();
  if (!name) {
    throw new Error("请填写菜品名称");
  }
  const categoryKey = (payload.categoryKey || "").trim();
  if (!categoryKey) {
    throw new Error("请选择菜品分类");
  }
  const coverUrl = (payload.coverUrl || "").trim();
  if (!coverUrl) {
    throw new Error("请上传菜品图片");
  }
  const description = (payload.description || "").trim();
  const stockValue = Number(payload.stock ?? 0);
  const funValueRaw = Number(payload.funValue ?? 0);
  const stock = Number.isFinite(stockValue) ? Math.max(0, Math.floor(stockValue)) : 0;
  const funValue = Number.isFinite(funValueRaw) ? Math.max(0, Math.floor(funValueRaw)) : 0;
  const now = new Date().toISOString();
  const menuItem: LocalMenuItem = {
    _id: generateId("menu"),
    chefOpenId: chef._openid,
    categoryKey,
    name,
    description,
    coverUrl,
    stock,
    funValue,
    isActive: payload.isActive ?? true,
    createdAt: now,
  };
  db.menu.unshift(menuItem);
  saveDB(db);
  return { menu: cloneMenuItem(menuItem) };
}

function updateMenu(payload: MenuSavePayload): MenuSaveResponse {
  const db = ensureDB();
  const chef = requireChef(db);
  if (!payload._id) {
    throw new Error("当前版本仅支持修改菜品");
  }
  const target = db.menu.find((item) => item._id === payload._id && item.chefOpenId === chef._openid);
  if (!target) {
    throw new Error("未找到菜品");
  }
  if (typeof payload.name === "string" && payload.name.trim()) {
    target.name = payload.name.trim();
  }
  if (typeof payload.categoryKey === "string" && payload.categoryKey) {
    target.categoryKey = payload.categoryKey;
  }
  if (typeof payload.description === "string") {
    target.description = payload.description.trim();
  }
  if (typeof payload.coverUrl === "string" && payload.coverUrl.trim()) {
    target.coverUrl = payload.coverUrl.trim();
  }
  if (typeof payload.stock === "number" && !Number.isNaN(payload.stock)) {
    target.stock = Math.max(0, Math.floor(payload.stock));
  }
  if (typeof payload.funValue === "number" && !Number.isNaN(payload.funValue)) {
    target.funValue = Math.max(0, Math.floor(payload.funValue));
  }
  saveDB(db);
  return { menu: { ...target } };
}

function removeMenu(payload: MenuRemovePayload): MenuRemoveResponse {
  const db = ensureDB();
  const chef = requireChef(db);
  const menuId = (payload.menuId || "").trim();
  if (!menuId) {
    throw new Error("缺少菜品 ID");
  }
  const index = db.menu.findIndex((item) => item._id === menuId && item.chefOpenId === chef._openid);
  if (index < 0) {
    throw new Error("未找到菜品");
  }
  db.menu.splice(index, 1);
  saveDB(db);
  return { menuId };
}

function toggleMenuStatusLocal(menuId: string, isActive: boolean) {
  const db = ensureDB();
  const chef = requireChef(db);
  const target = db.menu.find((item) => item._id === menuId && item.chefOpenId === chef._openid);
  if (!target) {
    throw new Error("未找到菜品");
  }
  target.isActive = isActive;
  saveDB(db);
  return { menu: { ...target } };
}

function listOrders(params: OrderListParams): OrderListResponse {
  const db = ensureDB();
  const user = requireUser(db);
  if (params.role === "chef" && user.role !== "chef") {
    throw new Error("请使用厨师账号");
  }
  if (params.role === "diner" && user.role !== "diner") {
    throw new Error("请使用点餐账号");
  }
  const orders = filterOrdersForUser(db, user, params.status);
  return { orders: orders.map(sanitizeOrder) };
}

function submitOrder(payload: OrderSubmitPayload): OrderSubmitResponse {
  const db = ensureDB();
  const diner = requireDiner(db);
  const aggregated = new Map<string, number>();
  const items = Array.isArray(payload.items) ? payload.items : [];
  for (const item of items) {
    const menuId = item.menuId;
    const quantity = Number(item.quantity || 0);
    if (!menuId || !quantity || quantity <= 0 || Number.isNaN(quantity)) {
      continue;
    }
    const prev = aggregated.get(menuId) || 0;
    aggregated.set(menuId, prev + Math.floor(quantity));
  }
  if (aggregated.size === 0) {
    throw new Error("请选择菜品");
  }

  const orderItems: OrderLineItem[] = [];
  let chefOpenId = "";

  for (const [menuId, quantity] of aggregated.entries()) {
    const menuItem = ensureMenuItem(db, menuId);
    if (!chefOpenId) {
      chefOpenId = menuItem.chefOpenId;
    }
    if (menuItem.chefOpenId !== chefOpenId) {
      throw new Error("一次只能向同一位厨师下单");
    }
    if (menuItem.stock < quantity) {
      throw new Error(`${menuItem.name} 库存只剩 ${menuItem.stock} 份啦`);
    }
  }

  for (const [menuId, quantity] of aggregated.entries()) {
    const menuItem = ensureMenuItem(db, menuId);
    menuItem.stock -= quantity;
    orderItems.push({
      menuId,
      name: menuItem.name,
      quantity,
      funValue: menuItem.funValue,
    });
  }

  const note = typeof payload.note === "string" ? payload.note.trim() : "";
  const order: LocalOrder = {
    _id: generateId("order"),
    chefOpenId,
    dinerOpenId: diner._openid,
    dinerNickname: diner.nickname,
    note: note || undefined,
    status: "pending",
    items: orderItems,
    createdAt: new Date().toISOString(),
    rejectReason: undefined,
    acceptedAt: undefined,
    startedAt: undefined,
    finishedAt: undefined,
    rejectedAt: undefined,
    closedAt: undefined,
  };

  db.orders.unshift(order);
  saveDB(db);

  return { order: sanitizeOrder(order) };
}

function acceptOrderLocal(orderId: string): OrderUpdateResponse {
  const db = ensureDB();
  const chef = requireChef(db);
  const order = ensureOrder(db, orderId);
  if (order.chefOpenId !== chef._openid) {
    throw new Error("只能操作自己的订单");
  }
  if (order.status !== "pending") {
    throw new Error("当前状态无法接单");
  }
  order.status = "accepted";
  order.acceptedAt = new Date().toISOString();
  order.rejectReason = undefined;
  order.rejectedAt = undefined;
  order.closedAt = undefined;
  saveDB(db);
  return { order: sanitizeOrder(order) };
}

function rejectOrderLocal(orderId: string, reason: string): OrderUpdateResponse {
  const db = ensureDB();
  const chef = requireChef(db);
  const order = ensureOrder(db, orderId);
  if (order.chefOpenId !== chef._openid) {
    throw new Error("只能操作自己的订单");
  }
  if (order.status !== "pending") {
    throw new Error("当前状态无法拒绝");
  }
  const rejectReason = (reason || "").trim();
  if (!rejectReason) {
    throw new Error("请填写拒绝原因");
  }
  order.status = "rejected";
  order.rejectReason = rejectReason;
  order.rejectedAt = new Date().toISOString();
  order.closedAt = order.rejectedAt;
  order.startedAt = undefined;
  order.finishedAt = undefined;
  order.acceptedAt = undefined;
  order.items.forEach((item) => {
    const menuItem = ensureMenuItem(db, item.menuId);
    if (menuItem.chefOpenId === chef._openid) {
      menuItem.stock += item.quantity;
    }
  });
  saveDB(db);
  return { order: sanitizeOrder(order) };
}

function startCooking(orderId: string): OrderUpdateResponse {
  const db = ensureDB();
  const chef = requireChef(db);
  const order = ensureOrder(db, orderId);
  if (order.chefOpenId !== chef._openid) {
    throw new Error("只能操作自己的订单");
  }
  if (order.status !== "accepted") {
    throw new Error("请先接单");
  }
  order.status = "cooking";
  order.startedAt = new Date().toISOString();
  saveDB(db);
  return { order: sanitizeOrder(order) };
}

function completeCooking(orderId: string): OrderUpdateResponse {
  const db = ensureDB();
  const chef = requireChef(db);
  const order = ensureOrder(db, orderId);
  if (order.chefOpenId !== chef._openid) {
    throw new Error("只能操作自己的订单");
  }
  if (order.status !== "cooking") {
    throw new Error("请先开始制作");
  }
  order.status = "completed";
  order.finishedAt = new Date().toISOString();
  order.closedAt = order.finishedAt;
  saveDB(db);
  return { order: sanitizeOrder(order) };
}

function getOrderDetail(orderId: string): OrderUpdateResponse {
  const db = ensureDB();
  const user = requireUser(db);
  const order = ensureOrder(db, orderId);
  if (user.role === "chef" && order.chefOpenId !== user._openid) {
    throw new Error("只能查看自己的订单");
  }
  if (user.role === "diner" && order.dinerOpenId !== user._openid) {
    throw new Error("只能查看自己的订单");
  }
  return { order: sanitizeOrder(order) };
}

function reviewOrder(payload: ReviewSubmitPayload): ReviewSubmitResponse {
  const db = ensureDB();
  const diner = requireDiner(db);
  const order = ensureOrder(db, payload.orderId);
  if (order.dinerOpenId !== diner._openid) {
    throw new Error("无法评价别人的订单");
  }
  if (order.status !== "completed") {
    throw new Error("请等厨师完成后再评价");
  }
  const rating = Math.min(5, Math.max(1, Number(payload.rating || 0)));
  if (!rating || Number.isNaN(rating)) {
    throw new Error("请给出星级评分");
  }
  order.review = {
    rating,
    comment: typeof payload.comment === "string" ? payload.comment.trim() : "",
    createdAt: new Date().toISOString(),
  };
  saveDB(db);
  return { order: sanitizeOrder(order) };
}

function registerUser(params: { account: string; password: string; nickname: string; role: RoleType }) {
  const { account, password, nickname, role } = params;
  if (!account || !password || !nickname) {
    throw new Error("请填写完整信息");
  }
  const db = ensureDB();
  if (db.users.some((user) => user.account === account)) {
    throw new Error("账号已存在");
  }
  if (role !== "chef" && role !== "diner") {
    throw new Error("角色不正确");
  }
  const openId = generateId("user");
  const user: LocalUser = {
    _id: generateId("user"),
    _openid: openId,
    account,
    nickname,
    avatarUrl: role === "chef" ? "https://img01.yzcdn.cn/vant/cat.jpeg" : "https://img.yzcdn.cn/vant/logo.png",
    role,
    createdAt: new Date().toISOString(),
    password,
  };
  db.users.push(user);
  saveDB(db);
  setActiveUser(user);
  return { user: sanitizeUser(user) };
}

function loginUser(params: { account: string; password: string }) {
  const { account, password } = params;
  const db = ensureDB();
  const user = db.users.find((item) => item.account === account && item.password === password);
  if (!user) {
    throw new Error("账号或密码错误");
  }
  setActiveUser(user);
  saveDB(db);
  return { user: sanitizeUser(user) };
}

function logoutUser() {
  setActiveUser(null);
  return {};
}

function updateProfile(payload: { nickname?: string; avatarUrl?: string }) {
  const db = ensureDB();
  const user = requireUser(db);
  if (payload.nickname && payload.nickname.trim()) {
    user.nickname = payload.nickname.trim();
  }
  if (payload.avatarUrl && payload.avatarUrl.trim()) {
    user.avatarUrl = payload.avatarUrl.trim();
  }
  saveDB(db);
  return { user: sanitizeUser(user) };
}

function ensureMenuItem(db: LocalDB, menuId: string): LocalMenuItem {
  const menuItem = db.menu.find((item) => item._id === menuId);
  if (!menuItem) {
    throw new Error("菜品不存在或已下架");
  }
  return menuItem;
}

function ensureOrder(db: LocalDB, orderId: string): LocalOrder {
  const order = db.orders.find((item) => item._id === orderId);
  if (!order) {
    throw new Error("订单不存在");
  }
  return order;
}

export function callLocalService<T>(action: string, payload: Record<string, any> = {}): T {
  switch (action) {
    case "bootstrap":
      return bootstrap() as unknown as T;
    case "authRegister":
      return registerUser(payload as { account: string; password: string; nickname: string; role: RoleType }) as T;
    case "authLogin":
      return loginUser(payload as { account: string; password: string }) as T;
    case "authLogout":
      return logoutUser() as T;
    case "profileUpdate":
      return updateProfile(payload as { nickname?: string; avatarUrl?: string }) as T;
    case "menuList":
      return listMenu() as unknown as T;
    case "menuCreate":
      return createMenu(payload as MenuCreatePayload) as unknown as T;
    case "menuUpdate":
      return updateMenu(payload as MenuSavePayload) as unknown as T;
    case "menuRemove":
      return removeMenu(payload as MenuRemovePayload) as unknown as T;
    case "menuToggle":
      return toggleMenuStatusLocal(payload.menuId, payload.isActive) as unknown as T;
    case "ordersList":
      return listOrders(payload as OrderListParams) as unknown as T;
    case "ordersSubmit":
      return submitOrder(payload as OrderSubmitPayload) as unknown as T;
    case "ordersAccept":
      return acceptOrderLocal(payload.orderId) as unknown as T;
    case "ordersReject":
      return rejectOrderLocal(payload.orderId, payload.reason) as unknown as T;
    case "ordersStart":
      return startCooking(payload.orderId) as unknown as T;
    case "ordersComplete":
      return completeCooking(payload.orderId) as unknown as T;
    case "ordersDetail":
      return getOrderDetail(payload.orderId) as unknown as T;
    case "ordersReview":
      return reviewOrder(payload as ReviewSubmitPayload) as unknown as T;
    default:
      throw new Error(`未实现的本地服务: ${action}`);
  }
}

export function clearLocalData() {
  wx.removeStorageSync(STORAGE_KEY);
  wx.removeStorageSync(USER_KEY);
  const fs = getFs();
  if (fs) {
    try {
      fs.unlinkSync(DB_FILE_PATH);
    } catch (error) {
      // ignore
    }
  }
}
